/* eslint-disable jsx-a11y/anchor-is-valid */
import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
import { Link, NavLink, Outlet, redirect, useLoaderData, useNavigation } from "@remix-run/react";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Theme, useTheme } from "remix-themes";
import { PermissionModel } from "~/.server/models/permission";
import { UserModel } from "~/.server/models/users";
import i18nServer from "~/i18n/i18n.server";
import { getSession } from "~/sessions.server";

export const meta: MetaFunction = () => {
  return [
    { title: "Remix Backend" },
    { name: "description", content: "Welcome to Remix Backend!" },
  ];
};

export async function loader({ request }: LoaderFunctionArgs) {
  const url = new URL(request.url);
  const pathname = url.pathname;
  // checking if login or not
  const session = await getSession(request.headers.get("cookie"));
  const user = session.get("user") as UserModel;
  const permissionPaths = session.get("permissionPaths") as string[];
  const permissions = session.get("permissions") as PermissionModel[];
  if (!user) {
    return redirect("/login");
  }
  // checking authentication
  if (pathname !== "/admin" && pathname !== "/admin/404" && !permissionPaths?.includes(pathname)) {
    return redirect("/admin/404");
  }

  const locale = await i18nServer.getLocale(request);
  const isZh = locale === "zh";
  // TODO 从session中取sidebars
  const sidebars = permissions || [];
  return {
    sidebars,
    isZh,
    pathname,
  }
}

// Avoid revalidating the loader function on every child request.
// export const shouldRevalidate = () => false;

export default function Admin() {
  const { sidebars, isZh, pathname } = useLoaderData<typeof loader>();
  const navigation = useNavigation();
  const [theme, setTheme] = useTheme();
  const { t } = useTranslation();
  const [isSidebarOpen, setIsSidebarOpen] = useState(true);
  const [isSidebarHover, setIsSidebarHover] = useState(false);
  const changeTheme = (e: React.ChangeEvent<HTMLInputElement>) => {
    e.target.checked ? setTheme(Theme.DARK) : setTheme(Theme.LIGHT);
  };

  const handleSidebarTitle = (item: PermissionModel) => {
    return (
      <>
        {item.icon && (
          <span>
            <i className={item.icon + " size-6"} />
          </span>
        )}
        {
          (!isSidebarOpen && !isSidebarHover)
            ? ""
            : <span className={`truncate transition-all duration-300 ease-in-out ${isSidebarOpen ? "opacity-100" : "opacity-0 w-0 group-hover:opacity-100 group-hover:w-max"}`}>
              {isZh ? (item.zh_name || item.name) : item.name}
            </span>
        }
      </>
    )
  }
  const handleSidebar = (item: PermissionModel) => {
    let open = false;
    if (item.children?.length) {
      item.children.forEach(item => {
        if (item.path && item.path === pathname) {
          open = true;
        }
      });
      return (
        <details className="transition-all duration-300 ease-in-out" open={open}>
          <summary>
            {handleSidebarTitle(item)}
          </summary>
          <ul className="transition-all duration-300 ease-in-out">
            {item.children.map((item) => {
              return (
                <li key={item.id}>
                  {handleSidebar(item)}
                </li>
              )
            })}
          </ul>
        </details>
      )
    } else {
      return (
        <>
          {item.path ? (
            <NavLink to={item.path}>
              {handleSidebarTitle(item)}
            </NavLink>
          ) : (
            <>
              {handleSidebarTitle(item)}
            </>
          )}
        </>
      )
    }
  }

  return (
    <div className="flex flex-auto bg-base-200 drawer min-h-screen">
      <input id="drawer-sidebar" type="checkbox" className="drawer-toggle" />
      {/* Sidebar */}
      <aside
        className={`hidden lg:block group flex-shrink-0 duration-300 ease-in-out bg-base-200 ${isSidebarOpen ? 'w-64' : 'w-24 hover:w-64 hover:-mr-40 z-10 bg-base-100'}`}
        onMouseEnter={() => setIsSidebarHover(true)}
        onMouseLeave={() => setIsSidebarHover(false)}
      >
        {/* icon和标题 */}
        <div className="flex px-4 pt-5 pb-2">
          <div>
            <svg xmlns="http://www.w3.org/2000/svg" className="size-7 w-10 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path strokeLinecap="round" strokeLinejoin="round" d="M6.429 9.75 2.25 12l4.179 2.25m0-4.5 5.571 3 5.571-3m-11.142 0L2.25 7.5 12 2.25l9.75 5.25-4.179 2.25m0 0L21.75 12l-4.179 2.25m0 0 4.179 2.25L12 21.75 2.25 16.5l4.179-2.25m11.142 0-5.571 3-5.571-3" />
            </svg>
          </div>
          <div className={`text-lg font-semibold truncate transition-all duration-300 ease-in-out ${isSidebarOpen ? "opacity-100" : "opacity-0 w-0 group-hover:opacity-100 group-hover:w-max"}`}>
            {t("app")}
          </div>
        </div>
        {/* 扩展的sidebar */}
        <ul className={`menu w-full ${(!isSidebarOpen && !isSidebarHover) ? "hidden" : ""}`}>
          {sidebars.map((item) => (
            <li key={item.id}>
              {handleSidebar(item)}
            </li>
          ))}
        </ul>
        {/* 收缩的sidebar */}
        <ul
          className={`menu w-full ${(isSidebarOpen || isSidebarHover) ? "hidden" : ""}`}
        >
          {sidebars.map((item) => (
            <li key={item.id}>
              {item.path ? (
                <NavLink to={item.path} end>
                  {handleSidebarTitle(item)}
                </NavLink>
              ) : (
                <>
                  {handleSidebarTitle(item)}
                </>
              )}
            </li>
          ))}
        </ul>
      </aside>
      {/* Mobile sidebar */}
      <aside className="drawer-side z-10">
        <label htmlFor="drawer-sidebar" aria-label="close sidebar" className="drawer-overlay"></label>
        <div className="flex flex-col bg-base-200 min-h-full w-80 p-4">
          <div className="flex px-4 py-2">
            <div>
              <svg xmlns="http://www.w3.org/2000/svg" className="size-7 w-10 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                <path strokeLinecap="round" strokeLinejoin="round" d="M6.429 9.75 2.25 12l4.179 2.25m0-4.5 5.571 3 5.571-3m-11.142 0L2.25 7.5 12 2.25l9.75 5.25-4.179 2.25m0 0L21.75 12l-4.179 2.25m0 0 4.179 2.25L12 21.75 2.25 16.5l4.179-2.25m11.142 0-5.571 3-5.571-3" />
              </svg>
            </div>
            <div className="text-lg font-semibold">
              {t("app")}
            </div>
          </div>
          <ul className="menu">
            {sidebars.map((item) => (
              <li key={item.id}>
                {handleSidebar(item)}
              </li>
            ))}
          </ul>
        </div>
      </aside>
      <div className="flex flex-col flex-auto min-h-screen w-screen lg:w-auto">
        <header>
          <div className="flex justify-between items-center max-w-screen-2xl py-2.5 mx-6 4xl:mx-auto">
            {/* sidebar toggle */}
            <div className="hidden lg:flex items-center">
              {/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
              <label className="swap swap-rotate btn btn-ghost btn-circle">
                <input type="checkbox" onChange={() => setIsSidebarOpen(!isSidebarOpen)} checked={isSidebarOpen} />
                <div className="swap-on">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
                    <path strokeLinecap="round" strokeLinejoin="round" d="m18.75 4.5-7.5 7.5 7.5 7.5m-6-15L5.25 12l7.5 7.5" />
                  </svg>
                </div>
                <div className="swap-off">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
                    <path strokeLinecap="round" strokeLinejoin="round" d="m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5" />
                  </svg>
                </div>
              </label>
              {/* Search input */}
              {/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
              <label className="input flex items-center gap-2 ml-4">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" className="size-4 opacity-70">
                  <path fillRule="evenodd" d="M9.965 11.026a5 5 0 1 1 1.06-1.06l2.755 2.754a.75.75 0 1 1-1.06 1.06l-2.755-2.754ZM10.5 7a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Z" clipRule="evenodd" />
                </svg>
                <input type="text" className="grow" placeholder="Search" />
              </label>
            </div>

            {/* Mobile sidebar toggle */}
            <div className="lg:hidden flex items-center">
              <label htmlFor="drawer-sidebar" aria-label="open sidebar" className="btn btn-xs btn-ghost">
                <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
                  <path strokeLinecap="round" strokeLinejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
                </svg>
              </label>
              {/* Search input */}
              <button className="btn btn-xs btn-ghost">
                <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
                  <path strokeLinecap="round" strokeLinejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
                </svg>
              </button>
            </div>

            {/* user info */}
            <div className="flex lg:gap-5 items-center">
              <div className="dropdown dropdown-end">
                <div tabIndex={0} role="button" className="btn btn-ghost btn-circle avatar">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
                    <path strokeLinecap="round" strokeLinejoin="round" d="m10.5 21 5.25-11.25L21 21m-9-3h7.5M3 5.621a48.474 48.474 0 0 1 6-.371m0 0c1.12 0 2.233.038 3.334.114M9 5.25V3m3.334 2.364C11.176 10.658 7.69 15.08 3 17.502m9.334-12.138c.896.061 1.785.147 2.666.257m-4.589 8.495a18.023 18.023 0 0 1-3.827-5.802" />
                  </svg>
                </div>
                <form>
                  <ul className="menu menu-sm dropdown-content bg-base-100 rounded-box z-[1] mt-3 w-52 p-2 shadow">
                    <li>
                      <button type="submit" name="lng" value="en" className="btn-ghost">English</button>
                    </li>
                    <li>
                      <button type="submit" name="lng" value="zh" className="btn-ghost">中文</button>
                    </li>
                  </ul>
                </form>
              </div>
              <label className="swap swap-rotate btn-ghost btn-circle">
                {/* this hidden checkbox controls the state */}
                <input type="checkbox" onChange={changeTheme} checked={theme === Theme.DARK} />
                {/* sun icon */}
                <svg
                  className="swap-off size-6 fill-current"
                  xmlns="http://www.w3.org/2000/svg"
                  viewBox="0 0 24 24">
                  <path
                    d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
                </svg>
                {/* moon icon */}
                <svg
                  className="swap-on size-6 fill-current"
                  xmlns="http://www.w3.org/2000/svg"
                  viewBox="0 0 24 24">
                  <path
                    d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
                </svg>
              </label>
              {/* user info */}
              <div className="dropdown dropdown-end">
                <div tabIndex={0} role="button" className="btn btn-ghost btn-circle avatar">
                  <div className="w-10 rounded-full">
                    <img
                      alt="Tailwind CSS Navbar component"
                      src="https://img.daisyui.com/images/stock/photo-1534528741775-53994a69daeb.webp" />
                  </div>
                </div>
                <ul className="menu menu-sm dropdown-content bg-base-100 rounded-box z-[1] mt-3 w-52 p-2 shadow">
                  <li>
                    <a className="justify-between">
                      Profile
                      <span className="badge">New</span>
                    </a>
                  </li>
                  <li><a>Settings</a></li>
                  <li>
                    <Link to="/logout">Logout</Link>
                  </li>
                </ul>
              </div>
            </div>
          </div>
        </header>
        <main className="mb-4">
          <div className={`
            max-w-screen-2xl ml-2 mr-6 4xl:mx-auto
            ${navigation.state === "loading" ? "opacity-25 transition-opacity duration-200 delay-200" : ""}
          `}>
            <Outlet />
          </div>
        </main>
      </div>
    </div>
  );
}
